package cp3120.net;

import cp3120.dao.DAOFactory;
import cp3120.model.User;
import cp3120.net.services.AccountManagerService;
import generic.net.Peer;
import generic.net.observers.PeerConnectObserver;
import generic.net.observers.PeerDisconnectObserver;
import generic.net.server.Object2ServiceAdapter;
import generic.net.server.Server;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Vector;

/**
 *
 * @author Adam Scarr <scarr.adam@gmail.com>
 */
public class AirportServer extends Server implements PeerConnectObserver, PeerDisconnectObserver, UserProvider {
    private static AirportServer instance;
    private Map<Thread, AirportPeer> clients = new HashMap<Thread, AirportPeer>();

    protected AirportServer() {
        getServiceManager().add(new Object2ServiceAdapter("RemoteUserService", DAOFactory.getUserDAO()));
        getServiceManager().add(new Object2ServiceAdapter("RemoteFlightService", DAOFactory.getFlightDAO()));
        getServiceManager().add(new Object2ServiceAdapter("RemotePurchaseService", DAOFactory.getPurchaseDAO()));
        getServiceManager().add(new Object2ServiceAdapter("RemoteVariableService", DAOFactory.getVariableDAO()));
        getServiceManager().add(new Object2ServiceAdapter(new AccountManagerService()));
        getPeerConnectDispatcher().add(this);
        getPeerDisconnectDispatcher().add(this);
        ActiveUser.setProvider(this);
    }

    public static AirportServer getInstance() {
        if (instance == null) {
            instance = new AirportServer();
        }

        return instance;
    }

    public List<User> getActiveUsers() {
        List<User> users = new Vector<User>();

        synchronized (clients) {
            for (AirportPeer client: clients.values()) {
                if (client.getUser() != null) {
                    users.add(client.getUser());
                }
            }
        }

        return users;
    }

    public boolean userIsActive(User user) {
        System.out.println("[Airport Server] Checking if " + user + " is active");
        synchronized (clients) {
            for (AirportPeer client: clients.values()) {
                if (client.getUser() != null && client.getUser().equals(user)) {
                    return true;
                }
            }
        }

        return false;
    }

    protected Peer createPeer() {
        return new AirportPeer();
    }

    public void peerConnect(Peer peer) {
        synchronized (peer) {
            AirportPeer client = (AirportPeer)peer;
            clients.put(client.getThread(), client);
        }
    }

    public void peerDisconnect(Peer peer) {
        synchronized (peer) {
            clients.remove(((AirportPeer)peer).getThread());
        }
    }

    public User getUser() {

        // Due to some racy scripts the server may have not initilised fully before receiving this request.
        AirportPeer client;
        do {
            client = clients.get(Thread.currentThread());
        } while (client == null);

        if (client.getUser() == null) {
            client.setUser(DAOFactory.getUserDAO().getUser("Anonymous"));
        }

        return client.getUser();
    }

    public void setUser(User user) {
        System.out.println("[Airport Server] Setting user for thread " + Thread.currentThread().getName() + " to " + user.getUsername());
        clients.get(Thread.currentThread()).setUser(user);
    }
}
